<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="text-css.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <style> .pre-box{border-left:3px solid grey;color:grey;width:700px;padding-left:15px;font-size:15px;background:#F5F5F5;}</style>
</head>
<body>
<div  class="box" style="display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;
">
    <a name="algor-add"><h1>加签算法</h1></a>
    <p>更新时间：2018-10-19 11:29:34</p>
    <a name="algor-add-1"><h2>1.构建加密字符串</h2></a>
    <pre class="pre-box">
        
String stringToSign=
HTTPMethod + "\n" +
Accept + "\n" + //建议显示设置 Accept Header。当 Accept 为空时，
部分 Http 客户端会给 Accept 设置默认值为 */*，导致签名校验失败。
Content-MD5 + "\n"
Content-Type + "\n" +
Date + "\n" +
Headers +
Url
    </pre>
 <p>HTTPMethod 为全大写，如 POST。</p>
    <p>Accept、Content-MD5、Content-Type、Date 如果为空也需要添加换行符”\n”，Headers如果为空不需要添加”\n”。</p>
    <h2>Content-MD5</h2>
    <p>Content-MD5 是指 Body 的 MD5 值，只有当 Body 非 Form 表单时才计算 MD5，计算方式为：</p>
    <pre class="pre-box">

String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8")));        
    </pre>
    <p>bodyStream 为字节数组。</p>
    <h2>Headers</h2>
    <p>Headers 是指参与 Headers 签名计算的 Header 的 Key、Value 拼接的字符串，建议对 X-Ca 开头以及自定义 Header 计算签名，注意如下参数不参与 Headers 签名计算：X-Ca-Signature、X-Ca-Signature-Headers、Accept、Content-MD5、Content-Type、Date。</p>
    <h3>Headers 组织方法：</h3>
    <p>先对参与 Headers 签名计算的 Header的Key 按照字典排序后使用如下方式拼接，如果某个 Header 的 Value 为空，则使用 HeaderKey + “:” + “\n”参与签名，需要保留 Key 和英文冒号。</p>
    <pre class="pre-box">

String headers =
HeaderKey1 + ":" + HeaderValue1 + "\n"\+
HeaderKey2 + ":" + HeaderValue2 + "\n"\+
...
HeaderKeyN + ":" + HeaderValueN + "\n"
    </pre>
    <p>将 Headers 签名中 Header 的 Key 使用英文逗号分割放到 Request 的 Header 中，Key为：X-Ca-Signature-Headers</p>
    <h2>Url</h2>
    <p>Url 指 Path + Query + Body 中 Form 参数，组织方法：对 Query+Form 参数按照字典对 Key 进行排序后按照如下方法拼接，如果 Query 或 Form 参数为空，则 Url = Path，不需要添加 ？，如果某个参数的 Value 为空只保留 Key 参与签名，等号不需要再加入签名。</p>
    <pre class="pre-box">

String url =
Path +
"?" +
Key1 + "=" + Value1 +
"&" + Key2 + "=" + Value2 +
...
"&" + KeyN + "=" + ValueN        
    </pre>
<p>注意这里Query或Form参数的Value可能有多个，多个的时候只取第一个 Value 参与签名计算。</p>
    <h2><a name="algor-add-2">2. 计算签名</a></h2>
    <pre class="pre-box">

Mac hmacSha256 = Mac.getInstance("HmacSHA256");
byte[] keyBytes = secret.getBytes("UTF-8");
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));
String sign = new String(Base64.encodeBase64(hmacSha256.doFinal(stringToSign
 .getBytes("UTF-8")),"UTF-8"));
    </pre>
    <p>secret 为 APP 的密钥。</p>
    <h2><a name="algor-add-3">3. 传递签名,传递密钥</a></h2>
    <p>将计算的密钥结果放到 Request 的 Header 中，Key为：X-Ca-Key。</p>
    <h2><a name="algor-add-4">4. 签名错误排查方法</a></h2>
    <p>当签名校验失败时，API网关会将服务端的 StringToSign 放到 HTTP Response 的 Header 中返回到客户端，Key为：X-Ca-Error-Message，只需要将本地计算的 StringToSign 与服务端返回的 StringToSign 进行对比即可找到问题；<br>
        如果服务端与客户端的 StringToSign 一致请检查用于签名计算的密钥是否正确；
        因为 HTTP Header 中无法表示换行，因此 StringToSign 中的换行符都被过滤掉了，对比时请忽略换行符。</p>
    <h2><a name="algor-add-5">5. 签名 demo</a></h2>
    <p>签名计算的详细 demo（JAVA）请参照链接：https://github.com/aliyun/api-gateway-demo-sign-java。</p>
</div>
<div id="intro-platform-nav" style="position:absolute;right:100px;top:150px;width:30px;height:30px;position:fixed;z-index:1;border:1px solid #CCC;box-shadow:4px 4px 10px #E8E8E8;border-radius:10px;background:#F5F5F5	">
    <img src="img\\sanheng.png" alt="" style="width:30px;height:30px;position:fixed;position:absolute;right:0px;top:0px;">
    <div  id="nav-text" style="display:none;line-height:15px;overflow:scroll;height:250px;overflow-x:hidden;padding-left:15px;">
        <p><a href="#algor-add">加签算法</a></p>
        <p><a href="#algor-add-1">1.构建加密字符串</a></p>
        <p><a href="#algor-add-2">2.计算签名</a></p>
        <p><a href="#algor-add-3">3.传递签名</a></p>
        <p><a href="#algor-add-4">4.签名错误排查方法</a></p>
        <p><a href="#algor-add-5">5.签名demo</a></p>
    </div>
</div>
</body>
<script src="jquery-3.3.1.min.js"></script>
<script>
    $(document).ready(function(){
      $("#intro-platform-nav").click(function(){
       $("#intro-platform-nav").animate({
            "width":"250px",
            "height":"250px"
       },600);
       $("#nav-text").css("display","");
    });
    $("#intro-platform-nav").mouseleave(function(){
      $("#intro-platform-nav").animate({
      "width":"30px",
      "height":"30px"
      },500);
      $("#nav-text").css("display","none");
    });
    })
</script>

</html>